/*
 *    Description:  组件
 *         Author:  fpktools, zxx@ashyelf.com
 *        Company:  ashyelf
 */

#include "land/farm.h"
/* 可使用的宏 
gPLATFORM             字符串, 编译的平台, 如mtk平台即为 "mtk" (此宏在SDK的顶层Makefile中定义)
HARDWARE              字符串, 编译的硬件(芯片), MT7628的芯片即为 "mt7628" (此宏在SDK的顶层Makefile中定义)
gCUSTOM               字符串, 编译的产品型号, 如D218的产品型号即为 "d218" (此宏在SDK的顶层Makefile中定义)
gPLATFORM__平台标识   宏定义, 如mtk平台会有 gPLATFORM__mtk 的宏定义
gHARDWARE__硬件标识   宏定义, 如MT7628芯片的硬件会有 gHARDWARE__mt7628 的宏定义
gCUSTOM__型号标识     宏定义, 如D218的产品会有 ggCUSTOM_d218 的宏定义
PROJECT_ID            字符串, 项目名称
COM_ID                字符串, 项目下的组件名称, 即本组件所在的目录名称
COM_IDPATH            字符串, 系统中的组件全称, 也就是 项目名@组件名
*/
/* 可使用的farm接口( 具体头文件在SDK顶层目录/doc/api目录 )
link.h              通用链表函数库
log.h               日志函数库
talk.h              json树函数库
misc.h              常用的杂项函数库
param.h             组件参数函数库
path.h              组件及配置的路径函数库
reg.h               系统全局变量函数库
serv.h              服务进程的函数库
joint.h             joint事件函数库
com.h               组件函数库
config.h            组件配置函数库
he.h                he指令函数库
project.h           项目资源相关的函数库
*/
/* 可使用的linux接口及宏
 * 与openwrt下普通的程序一样可以调用所有的linux支持的函数
 * 如要使用额外的头文件及库请在此目录下的mconfig中给出头文件位置及链接库, 具体见同目录下的mconfig文件
 * 以下函数会被不同的进程运行, 无法动态的共用全局变量, 如需共用全局变量请使用reg_set/reg_set接口（在land/reg.h中有说明)
*/



/* 组件使用说明, 返回一个字符串 
 * 用户可在he终端调用
    项目名/组件名.          获取此字符串帮助信息( 注意后面的点号不能少 )*/
const char *_intro( obj_t this )
{
    const char *helpstr = \
"{"\
"\n    \"setup\":\"setup the component\","\
"\n    \"shut\":\"shutdown the component\""\
"\n}\n";
    return helpstr;
}

/* 组件中setup函数, 通常用于初始化或部署此组件, 此函数通常还会在项目信息文件中注册为启动时即被调用
 * 用户可在he终端调用
    项目名@组件名.setup            调用此函数 */
talk_t _setup( obj_t this, param_t param )
{
    /* ############################################################### */
    /* #######  此处可增加启动代码， 以下是通用写法的示例     ############# */
    /* ############################################################### */

	// 默认根据组件配置的status属性来决定是否启动_service服务函数
	talk_t cfg;
	const char *ptr;

	/* 获取组件配置 */
	cfg = config_get( this, NULL );
	/* 得到组件配置的status属性值 */
	ptr = json_get_string( cfg, "status" );
	/* 判断值是否为enable */
	if ( ptr != NULL && 0 == strcmp( ptr, "enable") )
	{
		/* 将本组件的_service函数以服务的形式运行 */
		serv_start( this, "service", NULL, COM_IDPATH );
	}

	/* 释放组件配置 */
	talk_free( cfg );
	/* 退出, 记住一定要运行后立即退出, 如果不退出可能导致整个系统启动卡死在这里 */
    return ttrue;
}

/* 组件中shut函数, 通常用于关闭或退出此组件, 当系统关机时此组件需要关闭时可在项目信息文件中注册在系统关闭时调用
 * 用户可在he终端调用
    项目名@组件名.shut            调用此函数 */
talk_t _shut( obj_t this, param_t param )
{

    /* ############################################################### */
    /* #######  此处可增加关机代码， 以下是通用写法的示例     ############# */
    /* ############################################################### */

	/* 停止服务 */
	serv_stop( COM_IDPATH );

    return ttrue;
}

/* 组件中service函数, 通常在其它函数中将它作为服务进程启动, 所以它将一直运行, 如果它退出系统将重新启动它
 * 用户可在he终端调用
    项目名@组件名.service            调用此函数
   非常不建议在he终端以命令的方式去直接调用, 应使用serv_start等服务管理函数去启动它 */
talk_t _service( obj_t this, param_t param )
{

    /* ############################################################### */
    /* #######  此处可增加服务代码     ， 以下是示例程序一直记录日志####### */
    /* ############################################################### */

	/* 此函数正常不应该退出, 在_setup函数中将此函数设为服务将会导致 如果此函数退出系统将重新运行它（系统会尽量一直保持其运行） */
	const char *ptr;
	const char *livetime;
	char buffer[IDENTIFY_SIZE];
    talk_t m;

	/* 得到本组件配置property属性的值 */
	ptr = config_sgets( COM_IDPATH, "property", buffer, sizeof(buffer) );
	while( 1 )
	{
		/* 调用系统组件land@machine的status接口, 得到一个talk_t */
		m = com_scall( "land@machine", "status", NULL );
		/* 从land@machine.status返回的信息中得到livetime的属性, 即启动时长 */
		livetime = json_get_string( m, "livetime" );
		sleep( 30 );
		info( "Hello world, system run %s, I am weekup, property value is %s", livetime, ptr );
	}

    return tfalse;
}


/* 组件中take函数, 通常用于事件处理
 * 用户可在he终端调用
    项目名@组件名.take            调用此函数
   非常不建议在he终端以命令的方式去直接调用, 应注册事件处理， 让事件去调用它 */
talk_t _take( obj_t this, param_t param )
{

    /* ############################################################### */
    /* ####  此处可增加事件处理代码     ， 以下是示例记录事件发生日志 ##### */
    /* ############################################################### */

	/* 使用日志记录接收到的事件及事件携带的消息 */
    talk_t ms;
	char *ptr;
	const char *event;

	/* 得到事件名称 */
	event = param_option( param, 1 );
	/* 得到事件消息 */
	ms = param_talk( param, 2 );
	/* 将事件消息转换成字符串 */
	ptr = talk2string( ms );
	/* 记录事件 */
	info( "receive a event, name is %s, carry message is %s", event, ptr );

	/* 释放转换字符串时产生的内存 */
	free( ptr );
	/* 退出, 记住一定要运行后立即退出, 如果不退出可能导致整个事件处理卡死在这里 */
    return tfalse;
}



/* 查看组件配置时被触发调用的函数, 通常通过此函数得到实际的配置后再校准后再返回
 * 用户可在he终端直接查看组件配置
    项目名@组件名
    项目名@组件名:property */
talk_t _get( obj_t this, path_t path )
{
    talk_t cfg;

    /* 获取到的组件的配置参数 */
    cfg = config_get( this, path );

    /* ############################################################### */
    /* ##############  此处可增加校准操作     ######################## */
    /* ############################################################### */

    return cfg;
}
/* 设置组件参数时都会被触发调用到此函数, 通常通过此函数过滤后再存入实际的配置中去
 * 用户可在he终端直接修改组件配置
    项目名@组件名={"property":"property value"}
    项目名@组件名:property=property value  */
boole _set( obj_t this, path_t path, talk_t v )
{
    boole ret;

    /* ############################################################### */
    /* ##############  此处可增加过滤操作     ######################## */
    /* ############################################################### */

    /* 直接将设置的参数存入flash中 */
    ret = config_set( this, path, v );
    /* 如存入flash成功将调用通过先调用_shut关闭后再调用_setup来重启对应的服务 */
    if ( ret == true )
    {
        _shut( this, NULL );
        _setup( this, NULL );
    }
    return ret;
}



